<?php
/*
 Copyright 2006 Iván Montes, Morten Hundevad

 This file is part of FLV tools for PHP (FLV4PHP from now on).

 FLV4PHP is free software; you can redistribute it and/or modify it under the 
 terms of the GNU General var License as published by the Free Software 
 Foundation; either version 2 of the License, or (at your option) any later 
 version.

 FLV4PHP is distributed in the hope that it will be useful, but WITHOUT ANY 
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 A PARTICULAR PURPOSE. See the GNU General var License for more details.

 You should have received a copy of the GNU General var License along with 
 FLV4PHP; if not, write to the Free Software Foundation, Inc., 51 Franklin 
 Street, Fifth Floor, Boston, MA 02110-1301, USA
*/


/**
 * Serializes a PHP variable as an AMF stream
 *
 */
class FLV_Util_AMFSerialize {

	var $isLittleEndian;

	/**
	 * Class constructor
	 */
	function FLV_Util_AMFSerialize( )
	{
		//calculate endianness of the CPU
		$this->isLittleEndian = ( pack('s', 1) == pack('v', 1) );
	}
  
	/**
	 * Serializes a PHP variable into an AMF stream
	 *
	 * @param mixed $var	The variable to serialize
	 * @param bool	$skipMark	if true won't add the datatype mark
	 * @return The AMF stream
	 */
	function serialize( $var, $skipMark = false )
	{
	    // process objects as hashed arrays
	    if (is_object($var))
	    	$var = (array)$var;
	    	
	    if (is_array($var))
	    {
	        // find out if the array is numeric or associative
	        $numeric = true;
	   		foreach ( $var as $k=>$v )
	   		{
				if (!is_numeric($k))
				{
				    $numeric = false;
				    break;
				}
	   		}
	   		
	   		if ($numeric)
	   		{
		   		$data = ($skipMark?'':"\x0A") . pack('N', count($var));
	   		    foreach ( $var as $v )
	   			{
	   			    $data .= $this->serialize( $v );    
	   			}
	   		} else {


		   		$data = ($skipMark?'':"\x08") . pack('N', count($var));	   		    
	   		    foreach ( $var as $k=>$v )
	   		    {
	   		        $data .= $this->serialize((string)$k, true);
	   		        $data .= $this->serialize($v);
	   		    }
	   		    // end of sequence mark : empty string and 0x09 byte
	   		    $data .= $this->serialize('', true);
	   		    $data .= "\x09";
	   		}
	   			
	   		return $data;
	   		
	    } else if (is_null($var)) {
	        
	        return ($skipMark?'':"\x05");
	        
	    } else if (is_bool($var)) {
	        
	        return ($skipMark?'':"\x01") . ( $var ? "\x01" : "\x00" );
	        
	    } else if (is_numeric($var)) {
	    
	        $number .= pack('d', $var);
	        
			//reverse bytes if we are in little-endian hardware
			if ($this->isLittleEndian)
			{
			  $number = strrev( $number );
			}
			
			return ($skipMark?'':"\x00") . $number;
	        
	    } else if (is_string($var)) {
	        // check for a date
			if (preg_match('/^([0-9]{4})-?([0-9]{2})-?([0-9]{2})T([0-9]{2}):?([0-9]{2}):?([0-9]{2})(?:\.([0-9]{1,3}))?([Z+-])([0-9:]*)$/', trim($var), $m))
			{
				$seconds = mktime( $m[4], $m[5], $m[6], $m[2], $m[3], $m[1] );
				$ms = $seconds * 1000 + $m[7];
								
				if ($m[9])
				{				    
				    $ls = explode(':', $m[9]);
				    $tz = ($m[9]=='-' ? '-' : '') + $ls[0] * 60 + $ls[1];
				    $tz = pack('s', $tz);
				    if ($this->isLittleEndian)
				    	$tz = strrev($tz);
				}
				
				return ($skipMark?'':"\x0B") . $this->serialize((float)$ms, true) . pack('n', $tz);
			}

	        //we could push this upto 65536 I think but I feel safer like this
	        if (strlen($var) < 32768)
	        {
	            return ($skipMark?'':"\x02") . pack('n', strlen($var)) . $var;
	        } else {	            
	            return ($skipMark?'':"\x0C") . pack('N', strlen($var)) . $var;
	        }
	    } else {
	        
	        //if the datatype is not supported use a null value
	        return $this->serialize( NULL );
	        
	    }
	}
}
?>